package com.csp.anotation.mng;

import cn.hutool.core.bean.BeanUtil;
import com.csp.util.MethodUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 方法映射
 *
 * @author:chengsp
 * @createTime:2019/8/22 14:56
 */
public class MethodMapping {
    private static final String PLACEHOLDER_REGEX = "#\\{.+?\\}";
    private static final Pattern PATTERN = Pattern.compile(PLACEHOLDER_REGEX);
    /**
     * 方法
     */
    private Method method;
    /**
     * 返回类型
     */
    private ReturnType returnType;
    /**
     * 所属对象
     */
    private Object target;
    /**
     * 方法对应的注解
     */
    private Annotation annotation;
    /**
     * 原始sql
     */
    private String originalSql;
    /**
     * 预编译sql
     */
    private String preparedSql;

    /**
     * 方法返回值泛型类型
     */
    private Class returnGenericType;
    /**
     * 方法返回值类型
     */
    private Class returnClass;

    /**
     * sql参数列表名称
     */
    private List<String> paramList;

    public MethodMapping() {
    }


    public MethodMapping(Method method, ReturnType returnType, Object target, Annotation annotation) {
        this.method = method;
        this.returnType = returnType;
        this.target = target;
        this.annotation = annotation;
    }

    public MethodMapping(Method method, ReturnType returnType, Object target, Annotation annotation, String originalSql, String preparedSql, Class returnGenericType, Class returnClass, List<String> paramList) {
        this.method = method;
        this.returnType = returnType;
        this.target = target;
        this.annotation = annotation;
        this.originalSql = originalSql;
        this.preparedSql = preparedSql;
        this.returnGenericType = returnGenericType;
        this.returnClass = returnClass;
        this.paramList = paramList;
    }

    public void init() {
        Matcher m = PATTERN.matcher(originalSql);
        List<String> placeholders = new ArrayList<>();
        while (m.find()) {
            placeholders.add(m.group());
        }
        paramList = new ArrayList<>();
        for (String placeholder : placeholders) {
            placeholder = placeholder.replace("#{", "");
            placeholder = placeholder.replace("}", "");
            paramList.add(placeholder);
        }
        preparedSql = m.replaceAll("?");
        returnGenericType = getTClass();
        // 获取被调用的方法的参数名
        String[] methodParamNames = MethodUtil.getMethodParamNames(getMethod());
        /*Map<String, Object> methodArgsMap = new LinkedHashMap<>();
        for (int j = 0; j < methodParamNames.length; j++) {
            Object value = BeanUtil.getFieldValue(args[j], methodParamNames[j]);
            methodArgsMap.put(methodParamNames[j], value);
        }*/
    }

    private <T> Class<T> getTClass() {
        String typeName = getMethod().getGenericReturnType().getTypeName();
        StringBuilder className = new StringBuilder();
        for (int i = 0; i < typeName.length(); i++) {
            char c = typeName.charAt(i);
            if (c == '<') {
                while ((c = typeName.charAt(++i)) != '>') {
                    className.append(c);
                }
                break;
            }
        }
        if ("".equals(className.toString())) {
            return returnClass;
        } else {
            try {
                return (Class<T>) Class.forName(className.toString());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public ReturnType getReturnType() {
        return returnType;
    }

    public void setReturnType(ReturnType returnType) {
        this.returnType = returnType;
    }


    public Annotation getAnnotation() {
        return annotation;
    }

    public void setAnnotation(Annotation annotation) {
        this.annotation = annotation;
    }

    public String getOriginalSql() {
        return originalSql;
    }

    public void setOriginalSql(String originalSql) {
        this.originalSql = originalSql;
    }

    public String getPreparedSql() {
        return preparedSql;
    }

    public void setPreparedSql(String preparedSql) {
        this.preparedSql = preparedSql;
    }

    public Class getReturnGenericType() {
        return returnGenericType;
    }

    public void setReturnGenericType(Class returnGenericType) {
        this.returnGenericType = returnGenericType;
    }

    public List<String> getParamList() {
        return paramList;
    }

    public void setParamList(List<String> paramList) {
        this.paramList = paramList;
    }

    public Class getReturnClass() {
        return returnClass;
    }

    public void setReturnClass(Class returnClass) {
        this.returnClass = returnClass;
    }
}
